/*[Mandelbrotmenge]
 *Copyright (C) [08.06.2011]  [Nicklas Kulp]
 *
 *This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
 *
 *This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 *You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>.
 *
 *nicklas-kulp@gmx.de
 */

package Mandelbrotmenge;


import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFileChooser;

public class Mandelbrotmenge extends javax.swing.JFrame
{

    public Mandelbrotmenge()
    {
        initComponents();
    }

    @Override
    public void paint(Graphics g)
    {
        for(int x = 0; x <= this.getWidth(); x++)
        {
            for(int y = 0; y <= this.getHeight(); y++)
            {
                double re = 0, im = 0, rec = kx + zoom / this.getWidth() * x, imc = ky + zoom / this.getWidth() * y;
                double Farbe;
                for(Farbe = -1; Farbe <= Genauigkeit; Farbe++)
                {
                    if(re * re + im * im >= 4)
                    {
                        break;
                    }
                    double hilf = re * re - im * im + rec;
                    im = 2 * re * im + imc;
                    re = hilf;
                }
                boolean q = false;
                if(Farbe == Genauigkeit + 1)
                {
                    q = true;
                }
                Farbe *= Farben;
                Farbe += Farbe2;
                Farbe = Farbe % 360;

                g.setColor(getRGB(Farbe, Grau, Helligkeit));

                if(q)
                {
                    g.setColor(Color.black);
                }

                g.drawLine(x, y + 22, x, y + 22);
            }
        }
        if (Info)
        {
            String Beschreibung = "Mandelbrotmenge, X: " + kx + ", Y: " + ky + ", Zoom: " + 4 / zoom;
            g.setColor(Color.white);
            g.fillRect(this.getWidth() - 100, this.getHeight() - 30, 100, 30);
            g.fillRect(0, this.getHeight() - 30, 100, 30);
            g.fillRect((this.getWidth() - Beschreibung.length() * 8) / 2, this.getHeight() - 30, Beschreibung.length() * 8 - 40, 30);
            g.setColor(Color.black);
            g.drawString("Springe zu", this.getWidth() - 95, this.getHeight() - 12);
            g.drawString("Bild speichern", 5, this.getHeight() - 12);
            g.drawString(Beschreibung, (this.getWidth() - Beschreibung.length() * 8) / 2 + 20, this.getHeight() - 12);
        }
    }

    public Color getRGB(double Hue, double Saturation, double Value)
    {
        Color Farbe = null;
        Hue = Hue % 360;
        Value /= 255;

        if(Hue >= 0 && Hue <= 60)
        {
            Farbe = new Color((int) (255 * Value), (int) (Value * (Saturation + Hue / 60 * (255 - Saturation))), (int) (Value * Saturation));
        }
        if(Hue >= 60 && Hue <= 120)
        {
            Farbe = new Color((int) ((Saturation + (60 - (Hue - 60)) / 60 * (255 - Saturation)) * Value), (int) (255 * Value), (int) (Saturation * Value));
        }
        if(Hue >= 120 && Hue <= 180)
        {
            Farbe = new Color((int) (Saturation * Value), (int) (255 * Value), (int) ((Saturation + (Hue - 120) / 60 * (255 - Saturation)) * Value));
        }
        if(Hue >= 180 && Hue <= 240)
        {
            Farbe = new Color((int) (Saturation * Value), (int) ((Saturation + (60 - (Hue - 180)) / 60 * (255 - Saturation)) * Value), (int) (255 * Value));
        }
        if(Hue >= 240 && Hue <= 300)
        {
            Farbe = new Color((int) ((Saturation + (Hue - 240) / 60 * (255 - Saturation)) * Value), (int) (Saturation * Value), (int) (255 * Value));
        }
        if(Hue >= 300 && Hue <= 360)
        {
            Farbe = new Color((int) (255 * Value), (int) (Saturation * Value), (int) ((Saturation + (60 - (Hue - 300)) / 60 * (255 - Saturation)) * Value));
        }
        return Farbe;
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        addMouseWheelListener(new java.awt.event.MouseWheelListener() {
            public void mouseWheelMoved(java.awt.event.MouseWheelEvent evt) {
                formMouseWheelMoved(evt);
            }
        });
        addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                formMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                formMouseReleased(evt);
            }
        });
        addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                formKeyPressed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 964, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 725, Short.MAX_VALUE)
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void formMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_formMousePressed
        mausx = evt.getX();
        mausy = evt.getY();
    }//GEN-LAST:event_formMousePressed

    private void formMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_formMouseReleased

        if(Info && mausx >= this.getWidth() - 100 && evt.getX() >= this.getWidth() - 100 && mausy >= this.getHeight() - 30 && evt.getY() >= this.getHeight() - 30)
        {
            Positionseingabe bla = new Positionseingabe(this);
            bla.setVisible(true);
        }
        else
        {
            if(Info && mausx >= 0 && evt.getX() >= 0 && mausy >= this.getHeight() - 30 && evt.getY() >= this.getHeight() - 30)
            {
                JFileChooser chooser = new JFileChooser();
                chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
                chooser.setSelectedFile(new File("Mbm x:" + kx + " y:" + ky + " z:" + 4 / zoom));
                chooser.showSaveDialog(super.getContentPane());
                File Datei = chooser.getSelectedFile();
                BufferedImage Graphik = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
                if(!Datei.exists())
                {
                    Graphics g = Graphik.getGraphics();
                    for(int x = 0; x <= this.getWidth(); x++)
                    {
                        for(int y = 0; y <= this.getHeight(); y++)
                        {
                            double re = 0, im = 0, rec = kx + zoom / this.getWidth() * x, imc = ky + zoom / this.getWidth() * y;
                            double Farbe;
                            for(Farbe = 0; Farbe <= Genauigkeit; Farbe++)
                            {
                                if(re * re + im * im >= 4)
                                {
                                    break;
                                }
                                double hilf = re * re - im * im + rec;
                                im = 2 * re * im + imc;
                                re = hilf;
                            }
                            boolean q = false;
                            if(Farbe == Genauigkeit + 1)
                            {
                                q = true;
                            }
                            Farbe *= Farben;
                            Farbe += Farbe2;
                            Farbe = Farbe % 360;
                            g.setColor(getRGB(Farbe, Grau, Helligkeit));

                            if(q)
                            {
                                g.setColor(Color.black);
                            }

                            g.drawLine(x, y, x, y);
                        }
                    }
                    try
                    {
                        ImageIO.write(Graphik, "jpg", new File(chooser.getSelectedFile() + ".jpg"));
                    }
                    catch (IOException ex)
                    {
                    }
                }
            }
            else
            {
                if(mausx != evt.getX() && mausy != evt.getY())
                {
                    double zoom1 = 0, zoom2 = 0;
                    if(mausy < evt.getY())
                    {
                        ky = ky + zoom / this.getWidth() * (mausy - 22);
                        zoom1 = ((ky + zoom / this.getHeight() * evt.getY()) - (ky + zoom / this.getHeight() * mausy));
                    }
                    else
                    {
                        ky = ky + zoom / this.getWidth() * (evt.getY() - 22);
                        zoom1 = ((ky + zoom / this.getHeight() * mausy) - (ky + zoom / this.getHeight() * evt.getY()));
                    }
                    if(mausx < evt.getX())
                    {
                        kx = kx + zoom / this.getWidth() * mausx;
                        zoom2 = ((kx + zoom / this.getWidth() * evt.getX()) - (kx + zoom / this.getWidth() * mausx));
                    }
                    else
                    {
                        kx = kx + zoom / this.getWidth() * evt.getX();
                        zoom2 = ((kx + zoom / this.getWidth() * mausx) - (kx + zoom / this.getWidth() * evt.getX()));
                    }
                    if(zoom1 >= zoom2)
                    {
                        kx = kx + zoom2 / this.getWidth() * (mausx + evt.getX()) / 2;
                        zoom = zoom1;
                        kx = kx - 0.5 * zoom;
                    }
                    else
                    {
                        zoom = zoom2;
                        ky = ky + zoom1 / this.getWidth() * (mausy + evt.getY()) / 2;
                        ky = ky - 0.5 * zoom;
                    }
                    this.repaint();
                }
            }
        }
    }//GEN-LAST:event_formMouseReleased

    private void formMouseWheelMoved(java.awt.event.MouseWheelEvent evt) {//GEN-FIRST:event_formMouseWheelMoved
        double zoom1 = 0, zoom2 = 0;
        if(evt.getWheelRotation() == -1)
        {
            kx = kx + (zoom / this.getWidth() * evt.getX()) - 0.25 * zoom;
            ky = ky + (zoom / this.getHeight() * evt.getY()) - 0.25 * zoom;
            zoom = zoom * 0.5;
        }
        else
        {
            kx = kx + (zoom / this.getWidth() * evt.getX()) - 1 * zoom;
            ky = ky + (zoom / this.getHeight() * evt.getY()) - 1 * zoom;
            zoom = zoom * 2;
        }
        this.repaint();
    }//GEN-LAST:event_formMouseWheelMoved

    private void formKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_formKeyPressed
        if(evt.getKeyCode() == KeyEvent.VK_UP)
        {
            ky = ky - 0.05 * zoom;
            this.repaint();
        }
        if(evt.getKeyCode() == KeyEvent.VK_DOWN)
        {
            ky = ky + 0.05 * zoom;
            this.repaint();
        }
        if(evt.getKeyCode() == KeyEvent.VK_LEFT)
        {
            kx = kx - 0.05 * zoom;
            this.repaint();
        }
        if(evt.getKeyCode() == KeyEvent.VK_RIGHT)
        {
            kx = kx + 0.05 * zoom;
            this.repaint();
        }
        if(evt.getKeyCode() == KeyEvent.VK_PLUS)
        {
            kx = kx + 0.1 * zoom;
            ky = ky + 0.1 * zoom;
            zoom = zoom * 0.8;
            this.repaint();
        }
        if(evt.getKeyCode() == KeyEvent.VK_MINUS)
        {
            kx = kx - 0.125 * zoom;
            ky = ky - 0.125 * zoom;
            zoom = zoom * 1.25;
            this.repaint();
        }
        if(evt.getKeyCode() == KeyEvent.VK_Y)
        {
            if(Genauigkeit > 1)
            {
                Genauigkeit /= 2;
                this.repaint();
            }
        }
        if(evt.getKeyCode() == KeyEvent.VK_X)
        {
            Genauigkeit *= 2;
            this.repaint();
        }
        if(evt.getKeyCode() == KeyEvent.VK_A)
        {
            if(Farbe2 > 0)
            {
                Farbe2 -= 16;
                this.repaint();
            }
        }
        if(evt.getKeyCode() == KeyEvent.VK_S)
        {
            Farbe2 += 16;
            this.repaint();
        }
        if(evt.getKeyCode() == KeyEvent.VK_Q)
        {
            Farben *= 2;
            this.repaint();
        }
        if(evt.getKeyCode() == KeyEvent.VK_W)
        {
            Farben /= 2;
            this.repaint();
        }
        if(evt.getKeyCode() == KeyEvent.VK_C)
        {
            if(Grau > 0)
            {
                Grau -= 16;
                this.repaint();
            }
        }
        if(evt.getKeyCode() == KeyEvent.VK_V)
        {
            if(Grau < 240)
            {
                Grau += 16;
                this.repaint();
            }
        }
        if(evt.getKeyCode() == KeyEvent.VK_D)
        {
            if(Helligkeit > 16)
            {
                Helligkeit -= 16;
                this.repaint();
            }
        }
        if(evt.getKeyCode() == KeyEvent.VK_F)
        {
            if(Helligkeit < 250)
            {
                Helligkeit += 16;
                this.repaint();
            }
        }
        if(evt.getKeyCode() == KeyEvent.VK_I)
        {
            Info=!Info;
            this.repaint();
        }
        if(evt.getKeyCode() == KeyEvent.VK_SPACE)
        {

            kx = -2.5;
            ky = -1.5;
            zoom = 4;
            Genauigkeit = 360;
            Farbe2 = 0;
            Farben = 11.25 / 8;
            Grau = 0;
            Helligkeit = 255;
            this.repaint();
        }
    }//GEN-LAST:event_formKeyPressed

    /**
     * @param args the command line arguments
     */
    public static void main(String args[])
    {
        java.awt.EventQueue.invokeLater(new Runnable()
        {

            public void run()
            {
                Thread t = new Thread(this);
                new Mandelbrotmenge().setVisible(true);
            }
        });
    }
    int mausx, mausy, Genauigkeit = 360, Farbe2 = 0;
    double zoom = 4, kx = -2.5, ky = -1.5, Farben = 11.25 / 8, Grau = 0, Helligkeit = 255;
    boolean Info=false;
    // Variables declaration - do not modify//GEN-BEGIN:variables
    // End of variables declaration//GEN-END:variables
}
